package com.evolved.automata.android.bots.speechbot;
import android.app.*;
import android.content.*;
import android.content.res.*;
import android.graphics.AvoidXfermode.Mode;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

import com.evolved.automata.KeyValuePair;

import android.os.*;

public class InferenceController 
{
	private static String currentStateName="";
	private DataAccessApparatus dataModel;
	private LabelUpdater updater;
	private String PARAMETER_TYPE_INDICATOR="";
	private int ERROR_TOAST_DURATION_SEC=2;
	private InferenceApp context;
	private final static String NORMAL="NORMAL";
	private final static String DISPLAYING_SAVE_TEMPLATE_MENU_OPTION="DISPLAYING_SAVE_TEMPLATE_MENU_OPTION";
	private final static String LOAD_TEMPLATE_DIALOG_DISPLAYED="LOAD_TEMPLATE_DIALOG_DISPLAYED";
	
	public InferenceController(InferenceApp context, int size, String databaseName, boolean initialLoad,LabelUpdater lupdater)
	{
		this.context = context;
		updater=lupdater;
		Resources res = context.getResources();
		currentStateName = res.getString(R.string.CONTROLLER_STATE);
		PARAMETER_TYPE_INDICATOR = res.getString(R.string.parameter_type_indicator);
		ERROR_TOAST_DURATION_SEC = res.getInteger(R.integer.error_toast_duration_secs);
		dataModel = new DataAccessApparatus(context, size, databaseName, initialLoad);
		
		
	}
	
	
	private Hashtable<String,String> executeQuery(Hashtable<String,String> keyValueMap)
	{
		return dataModel.executeInferenceQuery(keyValueMap);
	}
	
	
	
	private void saveData(Hashtable<String,String> keyValueMap)
	{
		removeEmptyKeys(keyValueMap);
		dataModel.storeKeyValueMap(keyValueMap);
	}
	
	
	

	// TODO: make this a list
	private String[] getAllKeyNames()
	{
		return dataModel.getAllKeys();
	}
	
	// TODO: make this a list
	private String[] getAllValuesForKey(String key)
	{
		return dataModel.getValuesForKey(key);
	}
	
	
	
	private void removeEmptyKeys(Hashtable<String,String> keyValueMap)
	{
		for (String keyName:keyValueMap.keySet().toArray(new String[0]))
		{
			if (keyValueMap.get(keyName).length()==0)
				keyValueMap.remove(keyName);
		}
	}
	
	public void loadQuestionMap()
	{
		dataModel.loadQuestionModel();
	}
	
	
	public String[] processQuestionText(String questionText)
	{
		String[] consistentQuestions = dataModel.identifyQuestion(questionText);
		if (consistentQuestions==null) // Never heard of this question
		{
			return null;
		}
		Hashtable<String,String> worlds=new Hashtable<String, String>();
		if (consistentQuestions.length==1)
		{
			// Get all consistent worlds
			worlds.put(consistentQuestions[0],DataAccessApparatus.questionFilterKey );
			return getAllConsistentWorlds(worlds);
		}
		else
			if (consistentQuestions.length>1)
			{
				for (String questionKey:consistentQuestions)
				{
					worlds.put(questionKey, DataAccessApparatus.questionFilterKey);
				}
				return new String[]{StandardTools.serializeToString(worlds)};
			}
			else
			{
				return consistentQuestions;
			}
	}
	
	public void writeModelToFileRaw(String outputFileFullName)
	{
		
		java.io.File f = new java.io.File(outputFileFullName);
		if (f.exists())
			f.delete();
		Bundle[] allWorlds = dataModel.getAllStructuresFromDB();
		for (int i=0;i<allWorlds.length;i++)
			StandardTools.writeToFile(outputFileFullName, allWorlds[i].getString("structure"));
		
	}
	
	public void writeDebugModelOutput(String outputFileFullName)
	{
		java.io.File f = new java.io.File(outputFileFullName);
		if (f.exists())
			f.delete();
		
		Bundle[] allWorlds = dataModel.getAllStructuresFromDB();
		String lineOutputFormat="%1$s     %2$s";
		for (int i=0;i<allWorlds.length;i++)
			StandardTools.writeToFile(
					outputFileFullName, 
					String.format(lineOutputFormat, allWorlds[i].getInt("model_id"),allWorlds[i].getString("structure")));
					
			
	}
	
	public void writeWorldsToCSVFile(String outputFileFullname)
	{
		String[] keys = getAllKeyNames();
		String[] serializedWorlds =dataModel.getAllWorlds();
		StandardTools.writeModelsToCSV(outputFileFullname, keys, serializedWorlds);
	}
	
	public void writeWorldsToCSVFile(String outputFileFullname, Hashtable<String,String> consistentWorlds)
	{
		String[] serializedWorlds =dataModel.getConsistentWorlds(consistentWorlds);
		StandardTools.writeModelsToCSV(outputFileFullname, serializedWorlds);
	}
	
	public void writeWorldsToCSVFile(String outputFileFullname, String[] serializedWorlds)
	{
		StandardTools.writeModelsToCSV(outputFileFullname, serializedWorlds);
	}
	
	public void reloadModelFromRawFile(String outputFileFullName)
	{
		BufferedReader reader;
		String lineInput;
		Hashtable<String,String> modelValue;
		try
		{
			reader = new BufferedReader(new FileReader(outputFileFullName));
			dataModel.clearPermanentStorage();
			while ((lineInput=reader.readLine())!=null)
			{
				modelValue=StandardTools.parseToKeyValueMap(lineInput);
				dataModel.storeKeyValueMap(modelValue);
			}
		}
		catch (FileNotFoundException fException)
		{
			context.showErrorToast("Can not load model from file.  File does not exit.");
		}
		catch (IOException ie)
		{
			java.io.StringWriter traceText = new java.io.StringWriter();
			java.io.PrintWriter pWriter = new java.io.PrintWriter(traceText,true);
			ie.printStackTrace(pWriter);
			pWriter.close();
			throw new RuntimeException(pWriter.toString());
		}
	}
	
	public void importFromCSV(String inputFileFullName)
	{
		String[] loadedWorlds = StandardTools.importFromCSV(inputFileFullName);
		Hashtable<String,String> importMap;
		for (String loadedWorld:loadedWorlds)
		{
			importMap=StandardTools.parseToKeyValueMap(loadedWorld);
			dataModel.storeKeyValueMap(importMap);
		}
	}
	
	public String[] getFromCSV(String inputFileFullName)
	{
		String[] loadedWorlds = StandardTools.importFromCSV(inputFileFullName);
		return loadedWorlds;
	}
	
	public void synchronizeModelWithDB(List<Integer> worlds)
	{
		dataModel.synchronizeModelWithDB(worlds);
	}
	
	
	public String[] getAllConsistentWorlds(Hashtable<String,String> evidenceMap)
	{
		return dataModel.getConsistentWorlds(evidenceMap);		
	}
	
	public String[] getAllConsistentWorlds(Hashtable<String,String> evidenceMap,boolean strictP)
	{
		return dataModel.getConsistentWorlds(evidenceMap,strictP);		
	}
	
	public int changeValueInConsistentWorlds(Hashtable<String,String> keyValuePairs, String keyName, String keyValue)
	{
		return dataModel.processChangedKeyValue(keyValuePairs,keyName,keyValue);
	}
	
	public int removeKeyFromConsistentWorldIndices(List<Integer> worlds, String keyName)
	{
		return dataModel.removeKeyValueFromConsistentWorldIndices(worlds,keyName);
	}
	
	public int addKeyValueToConsistentWorlds(List<Integer> worlds, String keyName, String keyValue)
	{
		return dataModel.addKeyValueToConsistentWorldIndices(worlds,keyName, keyValue);
	}
	
	
	public boolean deleteConsistentWorlds(List<Integer> worlds)
	{
		return dataModel.deleteConsistentWorldIndices(worlds);
	}
	
	
	public List<Integer> getAllConsistentWorldIndices(Hashtable<String,String> evidenceMap)
	{
		return dataModel.getConsistentWorldIndices(evidenceMap);		
	}
	
	
	public int changeValueInConsistentWorldIndices(List<Integer> worlds, String keyName, String keyValue)
	{
		return dataModel.processChangedKeyValueIndices(worlds,keyName,keyValue);
	}
	
	public int removeKeyFromConsistentWorlds(Hashtable<String,String> keyValuePairs, String keyName)
	{
		return dataModel.removeKeyValueFromConsistentWorlds(keyValuePairs,keyName);
	}
	
	public int addKeyValueToConsistentWorlds(Hashtable<String,String> keyValuePairs, String keyName, String keyValue)
	{
		return dataModel.addKeyValueToConsistentWorlds(keyValuePairs,keyName, keyValue);
	}
	
	
	public boolean deleteConsistentWorlds(Hashtable<String,String> evidenceMap)
	{
		return dataModel.deleteConsistentWorlds(evidenceMap);
	}
	
	
	public Hashtable<String,String> extractParameterValues(Hashtable<String,String> keyValueMap)
	{
		Hashtable<String,String> parameterMap = new Hashtable<String, String>();
		String kValue;
		for (String keyName:keyValueMap.keySet().toArray(new String[0]))
		{
			if ((kValue=keyValueMap.get(keyName)).equalsIgnoreCase(PARAMETER_TYPE_INDICATOR))
			{
				parameterMap.put(keyName, kValue);
				keyValueMap.remove(keyName);
			}
		}
		return parameterMap;
	}
	
	private void deleteStructures()
	{
		dataModel.clearPermanentStorage();
	}
	
	public void deleteTemplates()
	{
		dataModel.clearAllTemplates();
	}
	
	public boolean saveKeyValueMap(Hashtable<String,String> keyValueMap)
	{
		saveData(keyValueMap);
		return true;
	}
	
	public Hashtable<String,String> executeInferenceOperation(Hashtable<String,String> keyValueMap)
	{
		return executeQuery(keyValueMap);
		
	}
	
	
	
	
	public String[] retrieveAllKeyNames()
	{
		return getAllKeyNames();
	}
	
	public String[] retrieveValuesForKey(String keyName)
	{
		return getAllValuesForKey(keyName);
	}
	
	public String[] retrieveValuesForKey(String keyName, int maxLength, boolean trimP)
	{
		String[] keys=getAllValuesForKey(keyName);
		LinkedList<String> truncated = new LinkedList<String>();
		for (String baseKey:keys)
		{
			if (baseKey.length()<=maxLength)
				truncated.add(baseKey);
			else
				if (trimP)
					truncated.add(baseKey.substring(0,maxLength));
		}
		return truncated.toArray(new String[0]);
	}
	
	
	
	
	
	public boolean deleteAllStructures()
	{
		deleteStructures();
		return true;
	}
	
	
	
}
